#include <everest/dbc/odbc/odbc_common.h>
#include <vector>
#include <string.h>
#include <stdio.h>

using namespace NS_EVEREST::dbc::odbc;
using namespace NS_EVEREST::dbc;
using namespace NS_EVEREST;
using namespace std;


OdbcPreparedStatement::OdbcPreparedStatement(SQLHANDLE hStm, OdbcConnection *pCon)
: OdbcStatement(hStm, pCon), m_paramCount(0)
{
	/*empty*/
}

OdbcPreparedStatement::~OdbcPreparedStatement() { }

void OdbcPreparedStatement::clearParameters()
{
	this->m_paramVector.clear();
}

void OdbcPreparedStatement::execute()
{
	SQLRETURN ret = SQL_SUCCESS;

	ret = SQLExecute(m_StmHandle);
	if ( ret == SQL_INVALID_HANDLE)
		throw OdbcException::InvalidHandle(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::execute{2}");
	else if ( ret == SQL_ERROR )
		throw OdbcException(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::execute{2}");
	return;
} // end OdbcPreparedStatement::execute()


IResultSet * OdbcPreparedStatement::executeQuery()
{
	SQLRETURN ret = SQL_SUCCESS;
	ret = SQLExecute(m_StmHandle);
	if ( ret == SQL_INVALID_HANDLE)
		throw OdbcException::InvalidHandle(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeQuery{2}");
	else if ( ret == SQL_ERROR )
		throw OdbcException(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeQuery{2}");

	SQLSMALLINT cols = 0;
	ret = SQLNumResultCols(m_StmHandle, &cols);
	if ( ret == SQL_ERROR) {
		throw OdbcException(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeQuery(){3}");
	} else if ( ret == SQL_INVALID_HANDLE) {
		throw OdbcException::InvalidHandle(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeQuery(){3}");
	} else if ( EVEREST_ODBC_SUCCESS(ret)) {
		return new OdbcResultSet(m_StmHandle, this->m_Conn, cols);
	}
	return new OdbcResultSet(m_StmHandle, this->m_Conn, 0, ret);
}

int OdbcPreparedStatement::executeUpdate()
{
	SQLRETURN ret = SQL_SUCCESS;
	ret = SQLExecute(m_StmHandle);
	if (ret == SQL_ERROR) {
		throw OdbcException(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeUpdate(){2}");
	} else if ( ret == SQL_INVALID_HANDLE ) {
		throw OdbcException::InvalidHandle(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeUpdate(){2}");
	} else if ( ret == SQL_STILL_EXECUTING) {
		return EXEC_STILL;
	} else if ( ret == SQL_NEED_DATA) {
		return EXEC_NEED_DATA;
	} else if ( ret == SQL_NO_DATA) {
		return EXEC_NO_DATA;
	} else {
		SQLLEN len = 0;
		ret = SQLRowCount(m_StmHandle, &len);
		if ( ret == SQL_ERROR) {
			throw OdbcException(SQL_HANDLE_STMT, m_StmHandle, "OdbcPreparedStatement::executeBatch(){3}");
		} else if ( EVEREST_ODBC_SUCCESS(ret) ) {
			return (int)len;
		} else {
			return EXEC_UNKNOWN;
		} // if ret
	}
}

IParameter * OdbcPreparedStatement::createParameter(ValueType vt, ParamInOutType inout, size_t colsize, int decimalDigits)
{
	SQLSMALLINT inOrOut;
	if (inout == PARAM_IN ) inOrOut = SQL_PARAM_INPUT;
	else if ( inout == PARAM_OUT ) inOrOut = SQL_PARAM_OUTPUT;
	else inOrOut = SQL_PARAM_INPUT_OUTPUT;

	OdbcParameter * param = new OdbcParameter(this->m_StmHandle, vt, inOrOut, (SQLULEN)colsize, (SQLSMALLINT)decimalDigits);
	return param;
}

bool OdbcPreparedStatement::addParameter(IParameter *pParam)
{
	OdbcParameter * param = dynamic_cast<OdbcParameter *>(pParam);
	if ( param == NULL ) return false;

	int idx = param->getIndex();    // param index starts from 1
	if (idx < 0 || idx > 65535 ) return false;

	if ( idx >= this->m_paramCount )
		this->m_paramCount = idx;
	if ( this->m_paramCount > (int)this->m_paramVector.size())
		this->m_paramVector.resize(this->m_paramCount);
	this->m_paramVector[idx - 1] = param;
	return param->bind();
}
